package handler

import (
	"context"
	"github.com/golang/protobuf/ptypes/empty"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"gorm.io/gorm"
	"pm_back_server/user-server/global"
	"pm_back_server/user-server/model"
	"pm_back_server/user-server/proto"
	"time"
)

const (
	UserNotFoundStr  = "用户不存在"
	UserAlreadyExist = "用户已存在"
)

type UserServer struct {
	proto.UnimplementedUserServer
}

func ModelToResponse(user model.User) *proto.UserInfoResponse {
	userInfoResponse := proto.UserInfoResponse{
		UserId:   uint64(user.ID),
		Password: user.Password,
		Nickname: user.Nickname,
		Mobile:   user.Mobile,
		Gender:   user.Gender,
		Role:     int32(user.Role),
	}
	if user.Birthday != nil {
		userInfoResponse.Birthday = uint64(user.Birthday.Unix())
	}
	return &userInfoResponse
}

func Paginate(page int, pageSize int) func(db *gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {
		if page == 0 {
			page = 1
		}

		switch {
		case pageSize > 100:
			pageSize = 100
		case pageSize <= 0:
			pageSize = 10
		}

		offset := (page - 1) * pageSize
		return db.Offset(offset).Limit(pageSize)
	}
}

// GetUserList /* 获取用户列表
func (s *UserServer) GetUserList(ctx context.Context, req *proto.PageInfo) (*proto.GetUserListResponse, error) {
	var users []model.User
	result := global.DB.Find(&users)
	if result.Error != nil {
		return nil, result.Error
	}

	rsp := &proto.GetUserListResponse{}
	rsp.PageTotal = int32(result.RowsAffected)

	global.DB.Scopes(Paginate(int(req.PageNumber), int(req.PageSize))).Find(&users)

	for _, user := range users {
		userInfoResponse := ModelToResponse(user)
		rsp.UserList = append(rsp.UserList, userInfoResponse)
	}

	return rsp, nil
}

// GetUserByMobile /* 通过手机号查询用户
func (s *UserServer) GetUserByMobile(ctx context.Context, req *proto.MobileRequest) (*proto.UserInfoResponse, error) {
	var user model.User
	result := global.DB.Where(&model.User{Mobile: req.Mobile}).First(&user)
	if result.RowsAffected == 0 {
		return nil, status.Errorf(codes.NotFound, UserNotFoundStr)
	}

	if result.Error != nil {
		return nil, result.Error
	}

	userInfoResponse := ModelToResponse(user)
	return userInfoResponse, nil
}

// GetUserById /* 通过用户id查询用户
func (s *UserServer) GetUserById(ctx context.Context, req *proto.IdRequest) (*proto.UserInfoResponse, error) {
	var user model.User
	result := global.DB.First(&user, req.UserId)
	if result.RowsAffected == 0 {
		return nil, status.Errorf(codes.NotFound, UserNotFoundStr)
	}

	if result.Error != nil {
		return nil, result.Error
	}

	userInfoResponse := ModelToResponse(user)
	return userInfoResponse, nil
}

// CreateUser /* 创建用户
func (s *UserServer) CreateUser(ctx context.Context, req *proto.CreateUserInfo) (*proto.UserInfoResponse, error) {
	var user model.User
	result := global.DB.Where(&model.User{Mobile: req.Mobile}).First(&user)
	if result.RowsAffected == 1 {
		return nil, status.Error(codes.AlreadyExists, UserAlreadyExist)
	}

	user.Mobile = req.Mobile
	user.Password = global.Encode(req.Password)

	result = global.DB.Create(&user)
	if result.Error != nil {
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}

	userInfoResponse := ModelToResponse(user)
	return userInfoResponse, nil
}

// UpdateUser /* 更新用户
func (s *UserServer) UpdateUser(ctx context.Context, req *proto.UpdateUserInfo) (*empty.Empty, error) {
	var user model.User
	result := global.DB.First(&user, req.UserId)
	if result.RowsAffected == 0 {
		return nil, status.Errorf(codes.NotFound, UserNotFoundStr)
	}

	birthday := time.Unix(int64(req.Birthday), 0)
	user.Nickname = req.Nickname
	user.Birthday = &birthday
	user.Gender = req.Gender

	result = global.DB.Save(&user)
	if result.Error != nil {
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}

	return &empty.Empty{}, nil
}

// CheckPassword /* 校验密码
func (s *UserServer) CheckPassword(ctx context.Context, req *proto.CheckPasswordInfo) (*proto.CheckResponse, error) {
	check := global.Verify(req.RawPassword, req.EncryptedPassword)
	return &proto.CheckResponse{
		Success: check,
	}, nil
}
